package org.dromara.common.social.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.enums.AuthUserGender;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import me.zhyd.oauth.request.*;
import org.dromara.common.core.service.ConfigService;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.gitea.AuthGiteaRequest;
import org.dromara.common.social.maxkey.AuthMaxKeyRequest;
import org.dromara.common.social.topiam.AuthTopIamRequest;

/**
 * 认证授权工具类
 *
 * @author thiszhc
 */
public class SocialUtils  {

    private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class);

    @SuppressWarnings("unchecked")
    public static AuthResponse<AuthUser> loginAuth(String source, String code, String state, SocialProperties socialProperties) throws AuthException {
        // 微信小程序登录特殊处理
        if ("wechat_mp".equals(source)) {
            return wechatMiniProgramLogin(code);
        }
        
        AuthRequest authRequest = getAuthRequest(source, socialProperties);
        AuthCallback callback = new AuthCallback();
        callback.setCode(code);
        callback.setState(state);
        return authRequest.login(callback);
    }

    /**
     * 微信小程序登录专用方法
     * 直接调用微信 jscode2session 接口，不使用 OAuth 流程
     */
    private static AuthResponse<AuthUser> wechatMiniProgramLogin(String code) throws AuthException {
        ConfigService configService = SpringUtils.getBean(ConfigService.class);
        
        // 检查微信小程序登录是否启用
        String enabled = configService.getConfigValue("wechat.mp.enabled");
        if (!"true".equals(enabled)) {
            throw new AuthException("微信小程序登录功能未启用");
        }
        
        // 获取微信小程序配置
        String appId = configService.getConfigValue("wechat.mp.appid");
        String appSecret = configService.getConfigValue("wechat.mp.secret");
        
        // 验证配置是否完整
        if (StrUtil.isBlank(appId)) {
            throw new AuthException("微信小程序AppID未配置");
        }
        if (StrUtil.isBlank(appSecret)) {
            throw new AuthException("微信小程序AppSecret未配置");
        }
        
        try {
            // 构造微信 jscode2session 请求URL
            String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                appId, appSecret, code
            );
            
            // 发送请求到微信服务器
            String response = HttpUtil.get(url);
            JSONObject jsonResponse = JSONUtil.parseObj(response);
            
            // 检查微信API响应
            if (jsonResponse.containsKey("errcode") && jsonResponse.getInt("errcode") != 0) {
                throw new AuthException("微信小程序登录失败: " + jsonResponse.getStr("errmsg"));
            }
            
            // 获取用户信息
            String openid = jsonResponse.getStr("openid");
            String unionid = jsonResponse.getStr("unionid");
            String sessionKey = jsonResponse.getStr("session_key");
            
            if (StrUtil.isBlank(openid)) {
                throw new AuthException("未能获取到用户openid");
            }
            
            // 构造 AuthUser 对象
            AuthUser authUser = AuthUser.builder()
                .uuid(openid)
                .username(openid)
                .nickname("微信用户")
                .avatar("")
                .blog("")
                .company("")
                .location("")
                .email("")
                .remark("")
                .gender(AuthUserGender.UNKNOWN)
                .source("WECHAT_MINI_PROGRAM")
                .token(AuthToken.builder()
                    .accessToken(sessionKey)
                    .openId(openid)
                    .unionId(unionid)
                    .build())
                .build();
            
            // 构造响应
            AuthResponse<AuthUser> authResponse = new AuthResponse<>();
            authResponse.setCode(2000);
            authResponse.setMsg("Success");
            authResponse.setData(authUser);
            return authResponse;
            
        } catch (Exception e) {
            throw new AuthException("微信小程序登录失败: " + e.getMessage());
        }
    }

    public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException {
        // 微信小程序登录已经在 loginAuth 方法中特殊处理，这里不再处理
        if ("wechat_mp".equals(source.toLowerCase())) {
            throw new AuthException("微信小程序登录请使用专用的登录方法");
        }
        
        SocialLoginConfigProperties obj = socialProperties.getType().get(source);
         if (ObjectUtil.isNull(obj)) {
            throw new AuthException("不支持的第三方登录类型");
        }
        AuthConfig.AuthConfigBuilder builder = AuthConfig.builder()
            .clientId(obj.getClientId())
            .clientSecret(obj.getClientSecret())
            .redirectUri(obj.getRedirectUri())
            .scopes(obj.getScopes());
        return switch (source.toLowerCase()) {
            case "dingtalk" -> new AuthDingTalkV2Request(builder.build(), STATE_CACHE);
            case "baidu" -> new AuthBaiduRequest(builder.build(), STATE_CACHE);
            case "github" -> new AuthGithubRequest(builder.build(), STATE_CACHE);
            case "gitee" -> new AuthGiteeRequest(builder.build(), STATE_CACHE);
            case "weibo" -> new AuthWeiboRequest(builder.build(), STATE_CACHE);
            case "coding" -> new AuthCodingRequest(builder.build(), STATE_CACHE);
            case "oschina" -> new AuthOschinaRequest(builder.build(), STATE_CACHE);
            // 支付宝在创建回调地址时，不允许使用localhost或者127.0.0.1，所以这儿的回调地址使用的局域网内的ip
            case "alipay_wallet" -> new AuthAlipayRequest(builder.build(), socialProperties.getType().get("alipay_wallet").getAlipayPublicKey(), STATE_CACHE);
            case "qq" -> new AuthQqRequest(builder.build(), STATE_CACHE);
            case "wechat_open" -> new AuthWeChatOpenRequest(builder.build(), STATE_CACHE);
            case "taobao" -> new AuthTaobaoRequest(builder.build(), STATE_CACHE);
            case "douyin" -> new AuthDouyinRequest(builder.build(), STATE_CACHE);
            case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE);
            case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE);
            case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE);
            case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey(obj.getStackOverflowKey()).build(), STATE_CACHE);
            case "huawei" -> new AuthHuaweiV3Request(builder.build(), STATE_CACHE);
            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeV2Request(builder.agentId(obj.getAgentId()).build(), STATE_CACHE);
            case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE);
            case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE);
            case "maxkey" -> new AuthMaxKeyRequest(builder.build(), STATE_CACHE);
            case "topiam" -> new AuthTopIamRequest(builder.build(), STATE_CACHE);
            case "gitea" -> new AuthGiteaRequest(builder.build(), STATE_CACHE);
            default -> throw new AuthException("未获取到有效的Auth配置");
        };
    }

}

